package org.ling.xuan.action.check;

import cn.hutool.core.io.FileUtil;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.actionSystem.CommonDataKeys;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiClassObjectAccessExpression;
import com.intellij.psi.PsiCodeBlock;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiExpression;
import com.intellij.psi.PsiExpressionList;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.PsiMethod;
import com.intellij.psi.PsiMethodCallExpression;
import com.intellij.psi.PsiType;
import com.intellij.psi.PsiTypeCastExpression;
import com.intellij.psi.impl.source.PsiTypeElementImpl;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.ling.xuan.util.LxIoUtil;
import org.ling.xuan.util.LxOptional;

import java.io.File;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class LxPsiSpringCheckAction extends AnAction {
    @Override
    public void actionPerformed(@NotNull AnActionEvent e) {
        String filePath = LxOptional.of(e, c -> c.getDataContext().getData(CommonDataKeys.VIRTUAL_FILE).getPath()).orElse("");
        File targetFile = new File(LxIoUtil.getWorkHome()+"/psi-Spring/"+ Objects.requireNonNull(e.getProject()).getName()+".txt");
        FileUtil.del(targetFile);
        FileUtil.touch(targetFile);
        if (FileUtil.isFile(filePath) && filePath.endsWith(".java")) {
               parseFile(e.getProject(), new File(filePath),targetFile);
        } else if (FileUtil.isDirectory(filePath)) {
            List<File> fs = FileUtil.loopFiles(filePath, f -> f.getName().endsWith(".java"));
            ExecutorService executorService = Executors.newFixedThreadPool(30);
            for (int i = 0; i < fs.size(); i++) {
                File src = fs.get(i);
                executorService.submit(()->{
                    parseFile(e.getProject(),src,targetFile);
                });
            }
            executorService.shutdown();
        }
    }

    private  void parseFile(Project project, File file,File targetFile) {
        VirtualFile virtualFile = LocalFileSystem.getInstance().findFileByPath(file.getAbsolutePath());
        Application application = ApplicationManager.getApplication();
        application.runReadAction(()->{
            if(virtualFile!=null) {
                PsiFile psiFile = PsiManager.getInstance(project).findFile(virtualFile);
                List<String> ss = parsePsi(psiFile);
                FileUtil.appendLines(ss, targetFile, StandardCharsets.UTF_8);
            }
        });
    }

    public static List<PsiMethod> getAllMethods(PsiFile psiFile) {
        List<PsiMethod> methods = new ArrayList<>();
        // 获取所有 Java 类
        PsiClass[] classes = PsiTreeUtil.getChildrenOfType(psiFile, PsiClass.class);
        if (classes != null) {
            for (PsiClass psiClass : classes) {
                // 获取类中的所有方法
                PsiMethod[] classMethods = psiClass.getAllMethods();
                methods.addAll(Arrays.asList(classMethods));
            }
        }
        return methods;
    }

    public static List<String> parsePsi(PsiFile file) {
        List<String> types = new ArrayList<>();
        List<PsiMethod> methods = getAllMethods(file);
        for (PsiMethod method : methods) {
            // 获取方法体
            PsiCodeBlock methodBody = method.getBody();
            if (methodBody != null) {
                Collection<PsiElement> elements = PsiTreeUtil.findChildrenOfAnyType(methodBody, PsiElement.class);
                for (PsiElement element : elements) {
                    if (element instanceof PsiMethodCallExpression) {
                        String callText = element.getText();
                        if (callText.contains("SpringContextFactory") && callText.contains("getApplicationContext()") && callText.contains("getBean")) {
                            PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) element;
                            PsiExpressionList psiExpressionList = methodCallExpression.getArgumentList();
                            if (!psiExpressionList.isEmpty()) {
                                PsiExpression[] psiExpressions = psiExpressionList.getExpressions();
                                if (psiExpressions.length == 2 && psiExpressions[1] instanceof PsiClassObjectAccessExpression) {
                                    PsiClassObjectAccessExpression pco = (PsiClassObjectAccessExpression) psiExpressions[1];
                                    PsiElement pe = pco.getNavigationElement().getFirstChild();
                                    if (pe instanceof PsiTypeElementImpl) {
                                        PsiTypeElementImpl pel = (PsiTypeElementImpl) pe;
                                        if(pel.getType().getCanonicalText().contains("com.hundsun.lcpt")) {
                                            types.add(pel.getType().getCanonicalText());
                                        }
                                    }
                                } else if (psiExpressions.length == 1) {
                                    if (methodCallExpression.getParent() != null && methodCallExpression.getParent() instanceof PsiTypeCastExpression) {
                                        PsiTypeCastExpression castExpression = (PsiTypeCastExpression) methodCallExpression.getParent();
                                        PsiType castType = castExpression.getType();
                                        if (castType != null) {
                                            if(castType.getCanonicalText().startsWith("com.hundsun.lcpt")) {
                                                types.add(castType.getCanonicalText());
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return types;
    }

}
